namespace Jsl.FxCop
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using Microsoft.FxCop.Sdk;

    /// <summary>
    /// A helper class for events.
    /// </summary>
    public static class EventHelper
    {
        #region Public Methods
        /// <summary>
        /// Determines if the specified event is backed by an <see cref="EventHandlerList"/>.
        /// </summary>
        /// <param name="eventMember">The event to check.</param>
        /// <returns><b>true</b> if the specified event is backed by an <see cref="EventHandlerList"/>.</returns>
        public static bool EventIsBackedByEventHandlerList(EventNode eventMember)
        {
            if (eventMember == null)
            {
                throw new ArgumentNullException("eventMember");
            }

            // Get either the add or remove handler. We don't care which.
            var testMethod = eventMember.HandlerAdder;
            if (testMethod == null)
            {
                testMethod = eventMember.HandlerRemover;
                if (testMethod == null)
                {
                    return false;
                }
            }

            // Search for any call to the EventHandlerList. If there is one assume this event is backed by an EventHandlerList.
            foreach (var instruction in testMethod.Instructions)
            {
                if (InstructionHelper.IsMethodCall(instruction.OpCode))
                {
                    var method = (Method)instruction.Value;
                    if (method.DeclaringType.FullName == WellKnownTypeNames.EventHandlerList)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Builds a list of the event adds and removes in the method.
        /// </summary>
        /// <param name="method">The method to search.</param>
        /// <returns>The event adds and removes in the method.</returns>
        public static IList<EventInformation> EventsUsedInMethod(this Method method)
        {
            var eventInfos = new List<EventInformation>();
            new CciVisitor()
                .AddVisitor((MethodCall call) =>
                {
                    EventInformation eventInfo;
                    if (EventInformation.TryCreate(method, call, out eventInfo))
                    {
                        eventInfos.Add(eventInfo);
                    }
                })
                .Visit(method);

            return eventInfos;
        }
        #endregion Public Methods
    }
}